import { exec } from 'child_process';
import axios from 'axios';
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

/**
 * 表示git差异中的一个变更块
 * @interface ChangeHunk
 * @property {number} oldStart - 变更的起始行号（旧文件）
 * @property {number} oldLines - 变更的行数（旧文件）
 * @property {number} newStart - 变更的起始行号（新文件）
 * @property {number} newLines - 变更的行数（新文件）
 * @property {string[]} content - 变更的具体内容
 */
interface ChangeHunk {
    oldStart: number;
    oldLines: number;
    newStart: number;
    newLines: number;
    content: string[];
}

/**
 * 表示文件中的变更
 * @interface FileChange
 * @property {number} totalAdditions - 文件中总共添加的行数
 * @property {number} totalDeletions - 文件中总共删除的行数
 * @property {ChangeHunk[]} hunks - 文件中的变更块数组
 */
interface FileChange {
    totalAdditions: number;
    totalDeletions: number;
    hunks: ChangeHunk[];
}

/**
 * 表示文件的完整git变更条目
 * @interface GitChange
 * @property {string} file - 变更文件的路径
 * @property {string} status - 文件的git状态（如：'modified'已修改, 'added'已添加, 'deleted'已删除）
 * @property {FileChange} changes - 文件的详细变更信息
 * @property {string} [lastModified] - 可选，最后修改的时间戳
 * @property {number} [fileSize] - 可选，文件大小（字节）
 * @property {boolean} binary - 指示文件是二进制还是文本文件
 */
interface GitChange {
    file: string;
    status: string;
    changes: FileChange;
    lastModified?: string;
    fileSize?: number;
    binary: boolean;
}

export class GitChangeDetector {
    private workspaceRoot: string;

    constructor(workspaceRoot: string) {
        this.workspaceRoot = workspaceRoot;
    }

    private executeGitCommand(command: string): Promise<string> {
        return new Promise<string>((resolve, reject) => {
            exec(command, { cwd: this.workspaceRoot }, (error, stdout, stderr) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(stdout.trim());
                }
            });
        });
    }

    private async getFileDetails(filename: string): Promise<{ lastModified: string; fileSize: number }> {
        try {
            const stats = await fs.promises.stat(path.join(this.workspaceRoot, filename));
            return {
                lastModified: stats.mtime.toISOString(),
                fileSize: stats.size
            };
        } catch (error) {
            console.error(`Error getting file details: ${error}`);
            return {
                lastModified: new Date().toISOString(),
                fileSize: 0
            };
        }
    }

    private async getChangesForFile(filename: string, staged: boolean = false): Promise<FileChange | null> {
        try {
            const diffCommand = staged
                ? `git diff --cached -U0 "${filename}"`
                : `git diff -U0 "${filename}"`;

            const diffOutput = await this.executeGitCommand(diffCommand);
            if (!diffOutput) {
                return null;
            }

            const hunks: ChangeHunk[] = [];
            let totalAdditions = 0;
            let totalDeletions = 0;

            // 解析 diff 输出
            const lines = diffOutput.split('\n');
            let currentHunk: ChangeHunk | null = null;

            for (const line of lines) {
                if (line.startsWith('@@')) {
                    // 新的代码块开始
                    if (currentHunk) {
                        hunks.push(currentHunk);
                    }

                    const match = line.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
                    if (match) {
                        currentHunk = {
                            oldStart: parseInt(match[1]),
                            oldLines: match[2] ? parseInt(match[2]) : 1,
                            newStart: parseInt(match[3]),
                            newLines: match[4] ? parseInt(match[4]) : 1,
                            content: []
                        };
                    }
                } else if (currentHunk && (line.startsWith('+') || line.startsWith('-'))) {
                    // 添加或删除的行
                    if (line.startsWith('+')) {
                        totalAdditions++;
                    } else {
                        totalDeletions++;
                    }
                    currentHunk.content.push(line);
                }
            }

            if (currentHunk) {
                hunks.push(currentHunk);
            }

            return {
                totalAdditions,
                totalDeletions,
                hunks
            };
        } catch (error) {
            console.error(`Error getting changes for file ${filename}:`, error);
            return null;
        }
    }

    private async isBinaryFile(filename: string): Promise<boolean> {
        try {
            const output = await this.executeGitCommand(`git diff --numstat --staged "${filename}"`);
            return output.startsWith('-');
        } catch (error) {
            console.error(`Error checking if file is binary: ${error}`);
            return false;
        }
    }

    private async isGitRepository(directoryPath: string): Promise<boolean> {
        try {
            const gitPath = path.join(directoryPath, '.git');
            const stats = await fs.promises.stat(gitPath);
            return stats.isDirectory();
        } catch (error) {
            return false;
        }
    }

    async getChangedFiles(): Promise<GitChange[]> {
        try {
            const statusOutput = await this.executeGitCommand('git status --porcelain -u');
            const changes: GitChange[] = [];
            
            if (!statusOutput) {
                return changes;
            }

            const files = statusOutput.split('\n').filter(line => line.trim() !== '');
            
            for (const file of files) {
                const status = file.substring(0, 2);
                const filename = file.substring(3);

                // 检查是否是二进制文件
                const isBinary = await this.isBinaryFile(filename);
                
                // 获取文件的详细信息
                const { lastModified, fileSize } = await this.getFileDetails(filename);

                // 获取文件的具体更改
                let fileChanges: FileChange | null = null;

                if (!isBinary) {
                    // 只检查暂存区的更改
                    if (status[0] !== ' ' && status[0] !== '?') {
                        fileChanges = await this.getChangesForFile(filename, true);
                    }
                }

                // 只有当文件真的有更改时才添加到结果中
                if (fileChanges && (fileChanges.totalAdditions > 0 || fileChanges.totalDeletions > 0) || status.includes('D')) {
                    changes.push({
                        file: filename,
                        status: this.getStatusDescription(status),
                        changes: fileChanges || {
                            totalAdditions: 0,
                            totalDeletions: 0,
                            hunks: []
                        },
                        lastModified,
                        fileSize,
                        binary: isBinary
                    });
                }
            }

            return changes;
        } catch (error) {
            console.error('Error getting git changes:', error);
            throw error;
        }
    }

    private getStatusDescription(status: string): string {
        const statusMap: { [key: string]: string } = {
            'M': '已修改',
            'A': '已添加',
            'D': '已删除',
            'R': '已重命名',
            'C': '已复制',
            'U': '已更新但未合并',
            '??': '未跟踪'
        };

        return statusMap[status] || status;
    }

    async sendToApi(changes: GitChange[], apiUrl: string): Promise<void> {
        try {
            const response = await axios.post(apiUrl, { changes });
            console.log('Successfully sent changes to API:', response.data);
        } catch (error) {
            console.error('Error sending changes to API:', error);
            throw error;
        }
    }
}
